<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // Promise.all控制同时并发的数量
        // 缺点：一组一组执行，如果一组中有等待时间长的则会浪费时间
        // const urls = ['url1', 'url2', 'url3', 'url4']
        // const maxConcurrentNum = 10 // 最大并发数
        // function chunk(arr, chunk) {
        //     let res = []
        //     for(let i = 0; i < arr.length; i += chunk) {
        //         res.push(arr.slice(i, i + chunk))
        //     }
        //     return res
        // }
        // function fetchUrl(url) {
        //     return new Promise((resolve, reject) => {
        //         fetch(url).then(res => {
        //             resolve(res)
        //         }).catch(err => {
        //             reject(err)
        //         })
        //     })
        // }
        // const chunkUrls = chunk(urls, maxConcurrentNum)
        // (async function() {
        //     try {
        //         for(let urls of chunkUrls) {
        //             const promises = urls.map(url => fetchUrl(url))
        //             const results = await Promise.all(promises)
        //             console.log(results);
        //         }
        //     } catch(err) {
        //         console.log(err);
        //     }
        // })()
        // 其实更好的思路，定义一个池子，如果池子的大小小于并发数，则往池子里面加请求，否则则需要等待
        // 池子中的请求执行完毕，再进池子。池子中没执行完一个，就出去一个
        // const urlList = new Array(100).fill('xxx')
        // const pool = new Set() // 请求池
        // const waitQueue = [] // 等待队列
        // const request = url => {
        //     return new Promise((resolve, reject) => {

        //         const isFull = pool.size >= 10
        //         const fn = function () {
        //             const myRequest = fetch(url)
        //             myRequest.finally(() => {
        //                 pool.delete(fn)
        //                 const next = waitQueue.shift() // 出队
        //                 next && pool.add(next)
        //                 setTimeout(() => next?.()) // 这段代码需要不需要待定
        //             })
        //             myRequest.then(resolve)
        //             myRequest.catch(reject)
        //             return myRequest
        //         }
        //         if (isFull) {
        //             waitQueue.push(fn)
        //         } else {
        //             pool.add(fn);
        //             fn(); // 发送请求
        //         }
        //     })
        // }
        // for (let [index, url] of urlList.entries()) {
        //     request(url).then(() => console.log('===', index))
        // }
        function createMaxRequest(maxSize) {
            const pool = new Set()
            const waitQueue = []
            const request = (url, param, delay) => {
                return new Promise((resolve, reject) => {
                    const isFull = pool.size >= maxSize
                    const foo = function() {
                        console.log('foo执行');
                        
                        const myRequest = new Promise((resolve, reject) => {
                            setTimeout(() => {
                                resolve(url)
                            }, delay)
                        })
                        myRequest.finally(() => {
                            pool.delete(foo)
                            const next = waitQueue.shift()
                            next && pool.add(next)
                            // setTimeout(() => {
                                next?.()
                            // })
                        })
                        myRequest.then(resolve)
                        myRequest.catch(reject)
                        return myRequest
                    }
                    if(isFull) {
                        waitQueue.push(foo)
                    } else {
                        pool.add(foo)
                        foo()
                    }
                })
            }
            return request
        }
        const fn = createMaxRequest(2)
        fn('a.com', '', 1000).then(res => {
            console.log(res);
        })
        fn('b.com', '', 2000).then(res => {
            console.log(res);
        })
        fn('c.com', '', 5000).then(res => {
            console.log(res);
        })
        fn('d.com', '', 1000).then(res => {
            console.log(res);
        })
    </script>
</body>

</html>